package xkp.lesson2;

public class TestThreadSecurity {
    public static void main(String[] args) throws InterruptedException {
        Sale sale1 = new Sale();
        Sale sale2 = new Sale();
        Sale sale3 = new Sale();

        sale1.start();
        sale2.start();
        sale3.start();
        sale1.join();
        sale2.join();
        sale3.join();
        System.out.println("剩余票数:"+Sale.count);
        //此时完整模拟了线程安全问题
        //多个窗口买了重复卖了一张票

    }
}

//要有一个卖票的线程类
class Sale extends Thread{
    //票的资源应该是共享的
    //此处模拟共享资源
    public static Integer count = 300;

    /**
     * 此处使用同步关键字修饰方法
     * 同步方法与同步代码块的区别
     * 同步方法相当于synchronized(this){}
     * 同步方法，当多个线程调用某个对象中的方法是，作同步效果比较好
     */
    public synchronized void saleCount(){
        System.out.println(count--);

    }

    @Override
    public void run() {
        for(int i = 1; i <= 100; i++){
            //count--操作不是原子操作，可重入的,非线程安全
            //count--操作在底层其实分为三步
            //1、把count值从内存mov 到CPU的寄存器中   MOV指令
            //2、CPU对改值进行减一操作 add -1   add/del
            //3、把寄存器中运算过后的值MOV到内存中    MOV


            //当A线程在count--时，如果B来了，B等A执行完后再去执行
            //此时要做线程同步
            //synchronized同步关键字
            //Sale.class同步时使用的锁，任何一个对象都可以作为锁使用，但是这个对象必须要能被这几个线程访问到
            //建议此处直接使用共享资源作为锁
            synchronized (count){
                System.out.println(count--);
            }
            //saleCount();


            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
